/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#include "stdafx.h"
#include "渲染物体创建销毁.h"
#include "渲染物体管理.h"
#include "物体编辑/物体编辑.h"

#include <file_文件名数据.h>
#include <节点全局数据.h>
#include <core/文件块.h>



static std::set<S_Mesh*> g网格管理容器;


static void f_场景渲染物体_ID面参数修改(S_Object* ob, S_网格包& me, uint32 多维子元素) {
	S_物体* em = dynamic_cast<S_物体*>(ob);

	auto& push = f_df_推送常量<S_ConstPush_Mesh_Face>(me.m_常量推送);
	push.m_Offset_Tranform = em->m_变换矩阵.m_Mem.m_偏移;
	push.m_Ob_Color = f_PackData4X8({uint8(ob), uint8(uint64(ob)>>8), uint8(uint64(ob)>>16), 255});
	push.m_Ob_ShaderType = f_glsl_Build_ShaderType(DEF_3DShaderType_PerObColor, DEF_3DTranform_Normal);
}

static void f_场景渲染物体_光照面参数修改(S_Object* ob, S_网格包& me, uint32 多维子元素) {
	S_物体* em = dynamic_cast<S_物体*>(ob);

	auto& push = f_df_推送常量<S_ConstPush_Mesh_Face>(me.m_常量推送);
	push.m_Offset_Tranform = em->m_变换矩阵.m_Mem.m_偏移;
	push.m_Ob_Color = f_PackData4X8({150,150,150,255});
	push.m_Ob_ShaderType = f_glsl_Build_ShaderType(DEF_3DShaderType_PerObColor, DEF_3DTranform_Normal);
}


static void f_场景渲染物体_面参数修改(S_Object* ob, S_网格包& me, uint32 多维子元素) {
	S_物体* em = dynamic_cast<S_物体*>(ob);

	auto& push = f_df_推送常量<S_ConstPush_Mesh_Face>(me.m_常量推送);
	push.m_Offset_Tranform = em->m_变换矩阵.m_Mem.m_偏移;
	push.m_Ob_Color = f_PackData4X8({150,150,150,255});
	push.m_Ob_ShaderType = f_glsl_Build_ShaderType(DEF_3DShaderType_PerObColor, DEF_3DTranform_Normal);
}

static void f_场景渲染物体_边参数修改(S_Object* ob, S_网格包& me, uint32 多维子元素) {
	S_物体* em = dynamic_cast<S_物体*>(ob);

	auto& push = f_df_推送常量<S_ConstPush_Mesh_Line>(me.m_常量推送);
	push.m_Offset_Tranform = em->m_变换矩阵.m_Mem.m_偏移;
	push.m_Ob_Color = f_PackData4X8({20,20,25,255});
	push.m_Ob_ShaderType = f_glsl_Build_ShaderType(DEF_3DShaderType_PerObColor, DEF_3DTranform_Normal);
}

static void f_场景渲染物体_点参数修改(S_Object* ob, S_网格包& me, uint32 多维子元素) {
	S_物体* em = dynamic_cast<S_物体*>(ob);

	auto& push = f_df_推送常量<S_ConstPush_Mesh_Point>(me.m_常量推送);
	push.m_Offset_Tranform = em->m_变换矩阵.m_Mem.m_偏移;
	push.m_Ob_Color = f_PackData4X8({255,255,255,255});
	push.m_PointSize = 3.0;
	push.m_Ob_ShaderType = f_glsl_Build_ShaderType(DEF_3DShaderType_PerObColor, DEF_3DTranform_Normal);
}

static void f_场景渲染物体_框参数修改(S_Object* ob, S_网格包& me, uint32 多维子元素) {
	S_物体* em = dynamic_cast<S_物体*>(ob);

	auto& push = f_df_推送常量<S_ConstPush_Mesh_Line>(me.m_常量推送);
	push.m_Offset_Tranform = em->m_变换矩阵.m_Mem.m_偏移;
	push.m_Ob_Color = f_PackData4X8({220,220,225,255});
	push.m_Ob_ShaderType = f_glsl_Build_ShaderType(DEF_3DShaderType_PerObColor, DEF_3DTranform_Normal);
}

static void f_更新物体变换回调(S_物体* ob, const Mat44f* 父级变换) {
	mat4 mxx = f_ob_getMatrix(ob, ob->m_实例ID);
	mxx = f_glsl_removePostion(mxx);

	ob->m_包围盒 = f_me_计算物体包围盒(ob->m_Bound, *(Mat44f*)&mxx);
	auto& 框 = f_ob_get数据(ob, 3);
	f_me_fill顶点(框.m_Mesh, {S_VNTC{ob->m_包围盒.pos, ob->m_包围盒.size * 2,{}}} );
}





void f_OB_创建网格物体数据(S_设备环境& ctx, S_物体* ob) {
	ob->m_深度偏移 = 0;

	f_ob_set数据槽数量(ob, 4);

	S_Mesh* mesh_面 = f_surface_创建网格对象(nullptr, ctx, ctx.m_支持光追, E_网格数据枚举::e_Mesh_Vulkan);
	S_Mesh* mesh_边 = f_surface_创建实例(mesh_面, true, false, false, true, true, false);
	S_Mesh* mesh_点 = f_surface_创建实例(mesh_面, true, false, true, true, true, true);
	S_Mesh* mesh_盒 = f_surface_创建网格对象(nullptr, ctx, ctx.m_支持光追, E_网格数据枚举::e_Mesh_Vulkan);

	g网格管理容器.insert(mesh_面);
	g网格管理容器.insert(mesh_边);
	g网格管理容器.insert(mesh_点);
	g网格管理容器.insert(mesh_盒);

	auto& 面 = f_ob_set数据(ob, mesh_面, 0);
	auto& 边 = f_ob_set数据(ob, mesh_边, 1);
	auto& 点 = f_ob_set数据(ob, mesh_点, 2);
	auto& 盒 = f_ob_set数据(ob, mesh_盒, 3);

	边.m_深度偏移 = 0;

	f_ob_set材质(ob, ctx.m_绘图环境->m_3D渲染管线->m_管线_面[0], 0);
	f_ob_set材质(ob, ctx.m_绘图环境->m_3D渲染管线->m_管线_面[0], 0, 1);
	f_ob_set材质(ob, ctx.m_绘图环境->m_3D渲染管线->m_管线_线[0], 1);
	f_ob_set材质(ob, ctx.m_绘图环境->m_3D渲染管线->m_管线_点[0], 2);
	f_ob_set材质(ob, ctx.m_绘图环境->m_3D渲染管线->m_管线_盒[0], 3);

	f_me_网格常量推送初始化<S_ConstPush_Mesh_Face>(面);
	f_me_网格常量推送初始化<S_ConstPush_Mesh_Line>(边);
	f_me_网格常量推送初始化<S_ConstPush_Mesh_Point>(点);
	f_me_网格常量推送初始化<S_ConstPush_Mesh_Line>(盒);


	mesh_面->mf_参数设置回调 = f_场景渲染物体_面参数修改;
	mesh_边->mf_参数设置回调 = f_场景渲染物体_边参数修改;
	mesh_点->mf_参数设置回调 = f_场景渲染物体_点参数修改;
	mesh_盒->mf_参数设置回调 = f_场景渲染物体_框参数修改;

	mesh_面->m_绘制类型 = S_元素绘制类型::e_绘制类型_索引;
	mesh_边->m_绘制类型 = S_元素绘制类型::e_绘制类型_索引;
	mesh_点->m_绘制类型 = S_元素绘制类型::e_绘制类型_序列;
	mesh_盒->m_绘制类型 = S_元素绘制类型::e_绘制类型_序列;

	mesh_边->m_线宽 = 0.5;
	mesh_盒->m_线宽 = 0.5;



	ob->mf_更新变换 = f_更新物体变换回调;
}

void f_OB_销毁网格物体数据(S_物体* ob) {
	auto& mp = f_ob_get网格包(ob);

	for (auto& e : mp) {
		f_ob_销毁网格包(e);

		if (e.m_Mesh->m_引用计数 <= 0) {
			f_surface_销毁网格(e.m_Mesh);

			g网格管理容器.erase(e.m_Mesh);
		}
	}

	mp.clear();
}

void f_OB_复制网格物体数据(S_物体* ob, const S_物体* fromOb) {
	f_OB_创建网格物体数据(ob->m_Ctx, ob);

	auto& tmp = f_ob_get网格包(ob);
	auto& smp = f_ob_get网格包(fromOb);

	assert(tmp.size() == smp.size());
	
	uint32 num = smp.size();
	for (uint32 i = 0; i < num; ++i) {
		f_surface_Copy(tmp[i].m_Mesh, smp[i].m_Mesh);
	}

	tmp[0].m_Mesh->m_Bound;
	
	auto& mp_t = f_ob_get数据(ob, 0);
	auto& mp_s = f_ob_get数据(fromOb, 0);

	mp_t.m_多维材质槽[0] = mp_s.m_多维材质槽[0];
	mp_t.m_Mesh->mf_参数设置回调 = mp_s.m_Mesh->mf_参数设置回调;
}





void f_OB_置网格ID面材质(S_物体* ob) {
	auto& pl = ob->m_Ctx.m_绘图环境->m_3D渲染管线;
	auto& mp = f_ob_get数据(ob, 0);

	mp.m_多维材质槽[0] = pl->m_管线_面[0];
	mp.m_Mesh->mf_参数设置回调 = f_场景渲染物体_ID面参数修改;
}

void f_OB_置网格光照面材质(S_物体* ob) {
	auto& pl = ob->m_Ctx.m_绘图环境->m_3D渲染管线;
	auto& mp = f_ob_get数据(ob, 0);

	mp.m_多维材质槽[0] = pl->m_管线_单色光照面[0];
	mp.m_Mesh->mf_参数设置回调 = f_场景渲染物体_光照面参数修改;
}


void f_OB_ID网格面材质(S_设备环境& ctx) {
	auto& pl = ctx.m_绘图环境->m_3D渲染管线;

	for (auto& e : f_global_渲染物体()) {
		auto& mp = f_ob_get数据(e.second, 0);

		mp.m_多维材质槽[0] = pl->m_管线_面[0];
		mp.m_Mesh->mf_参数设置回调 = f_场景渲染物体_ID面参数修改;
	}
}

void f_OB_单色网格面材质(S_设备环境& ctx) {
	auto& pl = ctx.m_绘图环境->m_3D渲染管线;

	for (auto& e : f_global_渲染物体()) {
		auto& mp = f_ob_get数据(e.second, 0);

		mp.m_多维材质槽[0] = pl->m_管线_面[0];
		mp.m_Mesh->mf_参数设置回调 = f_场景渲染物体_面参数修改;
	}
}

void f_OB_光照网格面材质(S_设备环境& ctx) {
	auto& pl = ctx.m_绘图环境->m_3D渲染管线;

	for (auto& e : f_global_渲染物体()) {
		auto& mp = f_ob_get数据(e.second, 0);

		mp.m_多维材质槽[0] = pl->m_管线_单色光照面[0];
		mp.m_Mesh->mf_参数设置回调 = f_场景渲染物体_光照面参数修改;
	}
}


bool on_文件拖放_导入模型(C_Widget* self, const std::vector<std::u16string>& name, E_对话框类型 方式) {
	for (auto& e : name) {

		auto 后缀 = f_file_get文件名后缀(e);
		std::vector<S_物体*> objs;
		
		if (后缀 == u".fbx" || 后缀 == u".FBX") {
			objs = f_ob_loadFBX(f_str_u16_to_u8(e), 1.0, *S_节点框架::g_3D视口环境);
		}
		else if (后缀 == u".abc" || 后缀 == u".obj" || 后缀 == u".stl") {
			
		}

		for (auto& ob : objs) {
			f_OB_创建网格物体数据(*S_节点框架::g_3D视口环境, ob);

			auto& 面 = f_ob_get数据(ob, 0);
			auto& 边 = f_ob_get数据(ob, 1);

			
			f_polygon_构建边((S_多边形*)ob->m_多边形);
			f_polygon_构建多边形顶点关系((S_多边形*)ob->m_多边形);
			f_polygon_构建面与顶点关联((S_多边形*)ob->m_多边形);
			f_polygon_计算面法线((S_多边形*)ob->m_多边形);
			f_polygon_计算光滑法线((S_多边形*)ob->m_多边形);
			f_surface_多边形生成网格((S_多边形*)ob->m_多边形, 面.m_Mesh, 边.m_Mesh);

			f_OE_更新网格包围盒({ob});
			f_om_添加渲染物体({ob}, f_file_取文件名(e));
		}
		
	}
	return true;
}



void f_OB_加载模型(FILE* f, S_设备环境& ctx) {
	uint32 物体数量 = 0;

	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_模型物体) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		下一次读取数据指针 = f_文件块_读数据块(下一次读取数据指针, 物体数量);
	}


	std::set<S_物体*> 待添加物体;
	for (uint32 i = 0; i < 物体数量; ++i) {
		S_文件块 物体文件块 = f_file_读取文件块(f);

		auto 块类型 = E_节点工程文件块类型(物体文件块.m_块类型);
		if (块类型 == E_节点工程文件块类型::e_工程文件块_多边形) {
			const uint8* 下一次读取数据指针 = 物体文件块.m_data;

			S_物体* 物体[1] = {};
			下一次读取数据指针 = f_ob_Load物体(ctx, 物体, 下一次读取数据指针);
			下一次读取数据指针 = f_ob_Load多边形(物体[0]->m_多边形, 下一次读取数据指针);

			待添加物体.insert(物体[0]);
			//f_OB_创建网格物体数据(ctx, 物体[0]);
			//f_global_渲染物体()[物体[0]->m_Name] = 物体[0];
		}
	}

	S_框架::g_资源加载保存.f_添加加载物体(待添加物体);
}

void f_OB_保存模型(FILE* f) {
	
	uint32 物体数量 = f_global_渲染物体().size();

	auto 渲染物体块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_模型物体, S_引擎配置::g_文件版本号);
	{
		S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));
		f_文件块_写数据块(块, 物体数量);
		f_file_保存文件块(f, 渲染物体块, 块);
	}
	

	for (auto& e : f_global_渲染物体()) {
		auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_多边形, S_引擎配置::g_文件版本号);
		S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));
		
		f_ob_Save物体(e.second, 块);
		f_ob_Save多边形(e.second->m_多边形, 块, false);

		f_file_保存文件块(f, 文件块, 块);
	}

	//S_框架::g_资源加载保存.f_添加保存物体(待添加物体);
}








